﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OmronFinsUDP
{
    public class EtherNetPLCUDP
    {
        //定义空间
        public string PRemoteIP = "";
        public int PRemotePort = 0;
        /// <summary>
        /// 建立连接，返回链接结果。
        /// </summary>
        /// <param name="RemoteIP">PLC地址,例："192.168.250.1"</param>
        /// <param name="RemotePort">PLC端口号,例："9600"</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public short Link(string RemoteIP,int RemotePort, short timeOut = 3000)
        {
            bool pingSucceed=false;
            pingSucceed = Subroutine.PingCheck(RemoteIP, 500);
            short connectSucceed = -1;
            if (pingSucceed)
            {
                UdpClient udp = new UdpClient();
                IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort);
                byte[] dataSend = Encoding.Default.GetBytes("123");
                dataSend = HandShake();
                udp.Send(dataSend, dataSend.Length, ipe);
                byte[] dataRec ;
                try
                {
                    dataRec = udp.Receive(ref ipe);
                }
                catch (Exception ex)
                {

                    throw ex;
                }
                udp.Close();
                if (dataRec.Length > 0)
                {
                    connectSucceed = 0;
                    PRemoteIP = RemoteIP;
                    PRemotePort = RemotePort;
                }
                else
                    connectSucceed = -1;
            }


            return connectSucceed;
        }
        /// <summary>
        /// 读取字数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">(short)数量,CP1H-E EX经测试最大返回729个字</param>
        /// <param name="reData">返回字数据，1个字为2字节</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public short ReadWords(String mr, short ch, short cnt, out short[] reData)
        {
            reData = new short[(int)(cnt)];//储存读取到的数据
            short tempCnt=0;
            short tempCh=0;
            if (cnt>729)
            {
                tempCnt = (short)(cnt - 729);
                tempCh = (short)( ch + 729);
                cnt = 729;
            }
            int num = (int)(100 + cnt * 2);//接收数据(Text)的长度,字节数
            byte[] buffer = new byte[num];//用于接收数据的缓存区大小
            byte plcTypeCode = 0x00;
            //CIO_Word = 0xB0,
            //CIO_Bit = 0x30,
            //WR_Word = 0xB1,
            //WR_Bit = 0x31,
            //HR_Word =0xB2,
            //HR_Bit = 0x32,
            //AR_Word =0xB3,
            //AR_Bit = 0x33,
            //DM_Word = 0x82,
            //DM_Bit = 0x02
            plcTypeCode = GetMemoryCode(mr,"Word");


            UdpClient udp = new UdpClient();
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(PRemoteIP), PRemotePort);
            //byte[] dataSend = Encoding.Default.GetBytes("123");
            #region 命令说明
            ///发送指令
            ///命令头
            ///1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
            ///2 RSV 固定 00
            ///3 GCT 固定 02
            ///4 DNA 为目标网络号
            ///5 DA1 为目标节点号
            ///6 DA2 为目标单元号
            ///7 SNA 为源网络号
            ///8 SA1 为源节点号
            ///9 SA2 为源单元号
            ///10 SID 设置 00
            #endregion
            byte[] dataSend =  
                {
                0x80,           //1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
                0x00,             //2 RSV 固定 00
                02,             //3 GCT 固定 02
                00,             //4 DNA 为目标网络号
                0x00,             //5 DA1 为目标节点号,设置00即为通用读取。
                00,             //6 DA2 为目标单元号
                0x00,             //7 SNA 为源网络号
                0xc0,             //8 SA1 为源节点号
                00,             //9 SA2 为源单元号
                00,             //10 SID 设置 00
                01,             //11,12 0101读指令
                01,             //11,12 0101读指令
                plcTypeCode,    //13 DM区域代码 Memory area code
                Convert.ToByte((ch/0x100)%0x100),             //14,15,16 地址
                Convert.ToByte(ch%0x100),             //14,15,16 地址
                0x00,             //14,15,16 地址 (此字节可能是位地址)
                Convert.ToByte((cnt/0x100)%0x100),             //17,18 数量
                Convert.ToByte(cnt%0x100)              //17,18 数量
                };//发送数据
            udp.Send(dataSend, dataSend.Length, ipe);
            try
            {
                buffer = udp.Receive(ref ipe);
            }

            catch (Exception ex)
            {

                throw ex;
            }
            udp.Close();

            for (int i = 0; i < cnt; i++)
            {
                reData[i] = (short)(buffer[14 + i * 2] * 0x100 + buffer[14 + i * 2 + 1]);
            }
            short[] tempReData;
            if (tempCnt>0)//有多余数值才执行循环读取
            {
                ReadWords(mr, tempCh, tempCnt, out tempReData);
                tempReData.CopyTo(reData, 729);
                //reData.CopyTo(tempReData, 730);
            }

            short re=0;
            return re;
        }
        /// <summary>
        /// 读取单个字数据
        /// </summary>
        /// <param name="mr">(PlcMemoryType)数据类型</param>
        /// <param name="ch">(short)地址</param>
        /// <param name="reData">(short)返回字数据，1个字为2字节</param>
        /// <returns>
        /// (short),连接结果
        /// </returns>
        public short ReadWord(String mr, short ch, out short reData)
        {
            short[] temp;
            reData = new short();
            short re = ReadWords(mr, ch,1, out temp);
            reData=temp[0];
            if (re != 0)
                return -1;
            else
                return 0;
        }
        /// <summary>
        /// 读取浮点数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">数量</param>
        /// <param name="reData">返回浮点数据，1个浮点数为4字节</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public short ReadReals(String mr, short ch, short cnt, out float[] reData)
        {
            reData = new float[(int)(cnt)];//储存读取到的数据
            byte[] rd;
            ReadBytes(mr, ch, (short)(cnt * 2), out rd);
            for (int i = 0; i < cnt; i++)
            {
                byte[] tempBytes= { rd[i*2], rd[i*2+1] };
                reData[i] = BitConverter.ToSingle(tempBytes, 0);
            }
            short re = 0;
            return re;
        }
        /// <summary>
        /// 读取单个浮点数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="reData">返回浮点数据，1个浮点数为4字节</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public short ReadReal(String mr, short ch,  out float reData)
        {
            reData = new float();//储存读取到的数据
            float[] tempFloat;
            ReadReals(mr, ch, 1, out tempFloat);
            reData = tempFloat[0];
            short re = 0;
            return re;
        }
        /// <summary>
        /// 读取字符串
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">数量</param>
        /// <param name="reData">(String)返回字符串</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public short ReadString(String mr, short ch, short cnt, out string reData)
        {
            byte []rd;
            char[] rdc=new char [cnt+1];
            short re = 0;
            ReadBytes(mr, ch, cnt, out rd);
            for (int i = 0; i < cnt; i++)
            {
                if (rd[i]!=0)
                {
                    rdc[i] = (char)rd[i];
                }
            }
            reData = new string(rdc);
            return re;
        }
        /// <summary>
        /// 读取字节数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">数量</param>
        /// <param name="reData">返回字节数据</param>
        /// <returns>
        /// 连接结果
        /// </returns>
        public short ReadBytes(String mr, short ch, short cnt, out byte[] reData)
        {

            reData = new byte[(int)(cnt)];//储存读取到的数据
            short re = 0;
            short[] reWords;
            re = ReadWords(mr, ch, (short)(cnt / 2 + cnt % 2), out reWords);

            for (int i = 0; i < cnt; i++)
            {
                if (cnt%2==0)
                {

                
                reData[i] = (Byte)reWords[cnt % 0x100];
                }
                else
                {
                    reData[i] = (Byte)reWords[cnt / 0x100];
                }
            }

            return re;

        }
        /// <summary>
        /// 读取字节数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">数量</param>
        /// <param name="reData">返回字节数据</param>
        /// <returns>
        /// 连接结果
        /// </returns>
        public short GetBitStates(String mr, string chS, short cnt, out short [] reData)
        {
            short ch = 1;
            reData = new short[(int)(cnt)];//储存读取到的数据
            int num = (int)(100 + cnt * 2);//接收数据(Text)的长度,字节数
            byte[] buffer = new byte[num];//用于接收数据的缓存区大小
            byte plcTypeCode = 0x00;
            //CIO_Word = 0xB0,
            //CIO_Bit = 0x30,
            //WR_Word = 0xB1,
            //WR_Bit = 0x31,
            //HR_Word =0xB2,
            //HR_Bit = 0x32,
            //AR_Word =0xB3,
            //AR_Bit = 0x33,
            //DM_Word = 0x82,
            //DM_Bit = 0x02
            plcTypeCode = GetMemoryCode(mr,"Bit");

            UdpClient udp = new UdpClient();
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(PRemoteIP), PRemotePort);
            //byte[] dataSend = Encoding.Default.GetBytes("123");
            #region 命令说明
            ///发送指令
            ///命令头
            ///1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
            ///2 RSV 固定 00
            ///3 GCT 固定 02
            ///4 DNA 为目标网络号
            ///5 DA1 为目标节点号
            ///6 DA2 为目标单元号
            ///7 SNA 为源网络号
            ///8 SA1 为源节点号
            ///9 SA2 为源单元号
            ///10 SID 设置 00
            #endregion
            byte[] dataSend =
                {
                0x80,           //1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
                0x00,             //2 RSV 固定 00
                02,             //3 GCT 固定 02
                00,             //4 DNA 为目标网络号
                0x00,             //5 DA1 为目标节点号,设置00即为通用读取。
                00,             //6 DA2 为目标单元号
                0x00,             //7 SNA 为源网络号
                0xc0,             //8 SA1 为源节点号
                00,             //9 SA2 为源单元号
                00,             //10 SID 设置 00
                01,             //11,12 0101读指令
                01,             //11,12 0101读指令
                plcTypeCode,             //13 DM区域代码 Memory area code
                Convert.ToByte((ch/0x100)%0x100),             //14,15,16 地址
                Convert.ToByte(ch%0x100),             //14,15,16 地址
                0x00,             //14,15,16 地址 (此字节可能是位地址)
                Convert.ToByte((cnt/0x100)%0x100),             //17,18 数量
                Convert.ToByte(cnt%0x100)              //17,18 数量
                };//发送数据


            udp.Send(dataSend, dataSend.Length, ipe);
            try
            {
                buffer = udp.Receive(ref ipe);
            }

            catch (Exception ex)
            {

                throw ex;
            }
            for (int i = 0; i < cnt; i++)
            {
                reData[i] = (short)(buffer[14 + i * 2] * 0x100 + buffer[14 + i * 2 + 1]);
            }
            udp.Close();
            short re = 0;
            return re;
        }
        /// <summary>
        /// 读值方法-按位bit（单个）
        /// </summary>
        /// <param name="mr">(string)地址类型枚举:"CIO WR HR AR DM"</param>
        /// <param name="ch">地址000.00</param>
        /// <param name="reDaya">返回开关状态枚举EtherNetPLC.BitState，0/1</param>
        /// <returns></returns>
        public short GetBitState(String mr, string ch, out short reData)
        {
            short[] reTempData;
            GetBitStateS(mr, ch, 1, out reTempData);
            reData = reTempData[0];
            return 0;
        }
        public short GetBitStateS(String mr, string ch, short cnt, out short[] reData)
        {
            reData = new short[(int)(cnt)];
            byte[] buffer = new byte[31];//用于接收数据的缓存区大小
            short cnInt = short.Parse(ch.Split('.')[0]);
            //2020年9月27日tips：修改当为无小数位时，默认为第0位
            short cnBit = 0;
            if (ch.Split('.').Length > 1)
            {
                cnBit = short.Parse(ch.Split('.')[1]);
            }
            short tempCnt = 0;
            short tempCh = 0;
            if (cnt > 729)
            {
                tempCnt = (short)(cnt - 729);
                tempCh = (short)(cnInt + 729);
                cnt = 729;
            }
            byte plcTypeCode = 0x00;
            //CIO_Word = 0xB0,
            //CIO_Bit = 0x30,
            //WR_Word = 0xB1,
            //WR_Bit = 0x31,
            //HR_Word =0xB2,
            //HR_Bit = 0x32,
            //AR_Word =0xB3,
            //AR_Bit = 0x33,
            //DM_Word = 0x82,
            //DM_Bit = 0x02
            plcTypeCode = GetMemoryCode(mr, "Bit");


            UdpClient udp = new UdpClient();
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(PRemoteIP), PRemotePort);
            //byte[] dataSend = Encoding.Default.GetBytes("123");
            #region 命令说明
            ///发送指令
            ///命令头
            ///1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
            ///2 RSV 固定 00
            ///3 GCT 固定 02
            ///4 DNA 为目标网络号
            ///5 DA1 为目标节点号
            ///6 DA2 为目标单元号
            ///7 SNA 为源网络号
            ///8 SA1 为源节点号
            ///9 SA2 为源单元号
            ///10 SID 设置 00
            #endregion
            byte[] dataSend =
                {
                0x80,           //1 ICF：2进制： 1,0:command/1:respond,0,0,0,0,0,0:respond required/1:not required
                0x00,             //2 RSV 固定 00
                02,             //3 GCT 固定 02
                00,             //4 DNA 为目标网络号
                0x00,             //5 DA1 为目标节点号,设置00即为通用读取。
                00,             //6 DA2 为目标单元号
                0x00,             //7 SNA 为源网络号
                0xc0,             //8 SA1 为源节点号
                00,             //9 SA2 为源单元号
                00,             //10 SID 设置 00
                01,             //11,12 0101读指令
                01,             //11,12 0101读指令
                plcTypeCode,    //13 DM区域代码 Memory area code
                Convert.ToByte((cnInt/0x100)%0x100),             //14,15,16 地址
                Convert.ToByte(cnInt%0x100),             //14,15,16 地址
                Convert.ToByte(cnBit),             //14,15,16 地址 (此字节可能是位地址)
                Convert.ToByte((cnt/0x100)%0x100),             //17,18 数量
                Convert.ToByte(cnt%0x100)              //17,18 数量
                };//发送数据
            udp.Send(dataSend, dataSend.Length, ipe);
            try
            {
                buffer = udp.Receive(ref ipe);
            }

            catch (Exception ex)
            {

                throw ex;
            }
            udp.Close();

            for (int i = 0; i < cnt; i++)
            {
                reData[i] = (short)(buffer[14 + i * 2] * 0x100 + buffer[14 + i * 2 + 1]);
            }
            short[] tempReData;
            if (tempCnt > 0)//有多余数值才执行循环读取
            {
                ReadWords(mr, tempCh, tempCnt, out tempReData);
                tempReData.CopyTo(reData, 729);
                //reData.CopyTo(tempReData, 730);
            }

            short re = 0;
            return re;

        }

        /// <summary>
        /// 写值方法-按位bit（单个）
        /// </summary>
        /// <param name="mr">(string)地址类型枚举:"CIO WR HR AR DM"</param>
        /// <param name="ch">地址000.00</param>
        /// <param name="bs">开关状态枚举EtherNetPLC.BitState，0/1</param>
        /// <returns></returns>
        public short SetBitState(String mr, string ch, short bitState)
        {

                return -1;
            
        }
        public short WriteWords(String mr, short ch, short cnt, short[] inData)
        {
            return 0;
        }
        public short WriteWord(String mr, short ch, short inData)
        {
            return 0;
        }
        /// <summary>
        /// 关闭PLC操作对象的UDP连接（实际无用）
        /// </summary>
        /// <returns>
        /// 结果：0正常，-1异常
        /// </returns>
        public short Close()
        {
            try
            {
                return 0;
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>
        /// 将数据区字符转换为数据区格式
        /// </summary>
        /// <param name="str">CIO 输入输出，DM 存储区，</param>
        /// <returns>
        /// 数据区格式
        /// </returns>

        public EtherNetPLCUDP.PlcMemory str2PlcType(string str)
        {
            EtherNetPLCUDP.PlcMemory mr = EtherNetPLCUDP.PlcMemory.DM;
            switch (str)
            {
                case "DM":
                    mr = EtherNetPLCUDP.PlcMemory.DM;
                    break;
                case "CIO":
                    mr = EtherNetPLCUDP.PlcMemory.CIO;
                    break;
                default:
                    mr = EtherNetPLCUDP.PlcMemory.DM;
                    break;
            }

            return mr;
        }
        internal static byte[] HandShake()
        {
            #region fins command
            //byte[] array = new byte[20];
            //Heardr
            //array[0] = (byte)'F';
            //array[1] = (byte)'I';
            //array[2] = (byte)'N';
            //array[3] = (byte)'S';
            ////Length
            //array[4] = 0;
            //array[5] = 0;
            //array[6] = 0;
            //array[7] = 0X0C;//长度,
            ////Command
            //array[8] = 0;
            //array[9] = 0;
            //array[10] = 0;
            //array[11] = 0;
            ////Error Code
            //array[12] = 0;
            //array[13] = 0;
            //array[14] = 0;
            //array[15] = 0;
            ////Client Node Addredd
            //array[16] = 0;
            //array[17] = 0;
            //array[18] = 0;
            //array[19] = 0;//TODO:ask for client and server node number, the client node will allocated automatically
            #endregion fins command
            //string str1 = "80000200030000C000000101820064000001";
            //string str1 = "80 00 02 00  03 00 00 C0  00 00 01 01  82 00 64 00   0001";

            byte[] array = new byte[20];
            //Heardr
            //array[0] = 0x80;
            //array[1] = 0;
            //array[2] = 2;
            //array[3] = 0;
            ////Length
            //array[4] = 3;
            //array[5] = 0;
            //array[6] = 0;
            //array[7] =0xc0;//长度,
            ////Command
            //array[8] = 0;
            //array[9] = 0;
            //array[10] = 1;
            //array[11] = 1;
            ////Error Code
            //array[12] = 0x82;
            //array[13] = 0;
            //array[14] = 0x64;
            //array[15] = 0;
            ////Client Node Addredd
            //array[16] = 0;
            //array[17] = 1;



            return array;

        }
        internal static byte[] Command()
        {
            #region fins command
            //80 00 02 00 03 00 00 C000 00
            byte[] array = new byte[20];
            //Heardr
            array[0] = 0x80;//ICF
            array[1] = 0x00; //RSV 固定 00，
            array[2] = 0x02;//GCT 固定 02
            array[3] = 0x00;//DNA 为目标网络号
            array[4] = 0x03;// DA1 为目标节点号
            array[5] = 0x00;//DA2 为目标单元号
            array[6] = 0x00;//SNA 为源网络号
            array[7] = 0XC0;//SA1 为源节点号
            array[8] = 0x00;//SA2 为源单元号
            array[9] = 0x00;//SID 设置 00
            array[10] = 0;//MRC main request code
            array[11] = 0;// SRC Sub-request code
            //Command Code
            array[12] = 0;
            array[13] = 0;
            array[14] = 0;
            array[15] = 0;
            array[16] = 0;
            array[17] = 0;
            array[18] = 0;
            array[19] = 0;
            #endregion fins command
            //string str1 = "80000200030000C000000101820064000001";
            //string str1 = "80 00 02 00  03 00 00 C0  00 00 01 01  82 00 64 00   0001";

            //Heardr
            //array[0] = 0x80;
            //array[1] = 0;
            //array[2] = 2;
            //array[3] = 0;
            ////Length
            //array[4] = 3;
            //array[5] = 0;
            //array[6] = 0;
            //array[7] =0xc0;//长度,
            ////Command
            //array[8] = 0;
            //array[9] = 0;
            //array[10] = 1;
            //array[11] = 1;
            ////Error Code
            //array[12] = 0x82;
            //array[13] = 0;
            //array[14] = 0x64;
            //array[15] = 0;
            ////Client Node Addredd
            //array[16] = 0;
            //array[17] = 1;



            return array;

        }
        private static void InitializeUdpClient()
        {
            IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 60001);
            UdpClient udpClient = new UdpClient(RemoteIpEndPoint);
            //如果这里写while(true) 则会不停挂起异步接收操作，直到占满缓冲区间或队列。会报“由于系统缓冲区空间不足或队列已满，不能执行套接字上的操作”的错
            UdpState s = new UdpState(udpClient, RemoteIpEndPoint);
            udpClient.BeginReceive(EndReceive, s);
            //udpClient.Close();
        }
        private static void EndReceive(IAsyncResult ar)
        {
            try
            {
                UdpState s = ar.AsyncState as UdpState;
                if (s != null)
                {
                    UdpClient udpClient = s.UdpClient;

                    IPEndPoint ip = s.IP;
                    Byte[] receiveBytes = udpClient.EndReceive(ar, ref ip);
                    string msg = Encoding.UTF8.GetString(receiveBytes);
                    Console.WriteLine(msg);
                    //udpClient.Close();

                    //udpClient.BeginReceive(EndReceive, s);//在这里重新开始一个异步接收，用于处理下一个网络请求
                }
            }
            catch (Exception ex)
            {
                //处理异常
            }

        }
        public class UdpState
        {
            private UdpClient udpclient = null;

            public UdpClient UdpClient
            {
                get { return udpclient; }
            }

            private IPEndPoint ip;

            public IPEndPoint IP
            {
                get { return ip; }
            }

            public UdpState(UdpClient udpclient, IPEndPoint ip)
            {
                this.udpclient = udpclient;
                this.ip = ip;
            }
        }
        public enum PlcMemory
        {
            //CIO_Word = 0xB0,
            //CIO_Bit = 0x30,
            //WR_Word = 0xB1,
            //WR_Bit = 0x31,
            //HR_Word =0xB2,
            //HR_Bit = 0x32,
            //AR_Word =0xB3,
            //AR_Bit = 0x33,
            //DM_Word = 0x82,
            //DM_Bit = 0x02
            /// <summary>
            /// PLC存储区类型
            /// 
            /// </summary>
            CIO,
            WR,
            HR,
            AR,
            DM,
            Timer,
            Conter,
            LR,
            
        }
        public enum MemoryType
        {
            Bit,
            Word
        }
        /// <summary>
        /// 数据类型,PLC字为16位数，最高位为符号位，负数表现形式为“取反加一”
        /// </summary>
        public enum DataType
        {
            BIT,
            INT16,
            REAL
        }
        /// <summary>
        /// bit位开关状态，on=1，off=0
        /// </summary>
        public enum BitState
        {
            ON = 1,
            OFF = 0
        }
        /// <summary>
        /// 区分指令的读写类型
        /// </summary>
        public enum RorW
        {
            Read,
            Write
        }
        /// <summary>
        /// 读取浮点数据
        /// </summary>
        /// <param name="mr">数据类型</param>
        /// <param name="ch">地址</param>
        /// <param name="cnt">数量</param>
        /// <param name="reReal">返回浮点数据，1个浮点数为4字节</param>
        /// <returns>
        /// bool,连接结果
        /// </returns>
        public byte PCNode = 0;

        /// <summary>
        /// 获取内存区码
        /// </summary>
        /// <param name="mr">(string)寄存器类型:"CIO WR HR AR DM"</param>
        /// <param name="mt">地址类型</param>
        /// <returns></returns>
        public byte GetMemoryCode(String mr, String mt)
        {

            if (mt == "Bit")
            {
                switch (mr)
                {
                    case "CIO":
                        return 0x30;
                    case "WR":
                        return 0x31;
                    case "HR":
                        return 0x32;
                    case "AR":
                        return 0x33;
                    case "DM":
                        return 0x02;
                    default:
                        return 0x00;
                }
            }
            else
            {
                switch (mr)
                {
                    //case "CIO":
                    //    return 0xB0;
                    //case "WR":
                    //    return 0xB1;
                    //case "HR":
                    //    return 0xB2;
                    //case "AR":
                    //    return 0xB3;
                    //case "DM":
                    //    return 0x82;
                    //default:
                    //    return 0x00;

                    case "CIO":
                        return  0x80;
                    case "WR":
                        return  0xB1;
                    case "HR":
                        return  0xB2;
                    case "AR":
                        return  0xB3;
                    case "DM":
                        return  0x82;
                    case "Timer":
                        return  0x81;
                    case "Conter":
                        return  0x82;
                    case "LR":
                        return  0x80;
                    default:
                        return 0x00;
                
                }
            }
        }

    }
}
